package com.jp.juc.locks;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;


public class UseReentrantLock {


    public static void main(String[] args) throws InterruptedException {
        // 公平 非公平
        // 默认非公平
        t1();
        //t2();
        //lockInterruptiblyTest();
    }


    /**
     * 锁获取打断
     */
    private static void lockInterruptiblyTest() {
        ReentrantLock reentrantLock = new ReentrantLock();

        new Thread(() -> {
            reentrantLock.lock();
            try {
                try {
                    System.out.println("A开始处理");
                    Thread.sleep(10000);
                } finally {
                    reentrantLock.unlock();
                }
            } catch (InterruptedException e) {
                System.out.println("A被中断");
                e.printStackTrace();
            }

        }, "A").start();


        Thread threadB = new Thread(() -> {
            try {
                System.out.println("B开始处理");
                reentrantLock.lockInterruptibly();
                try {
                    System.out.println("B执行任务");
                } finally {
                    reentrantLock.unlock();
                }
            } catch (InterruptedException e) {
                System.out.println("B被中断");
                e.printStackTrace();
            }
        }, "B");

        threadB.start();

        try {
            Thread.sleep(20);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        // 打断B
        threadB.interrupt();

    }


    private static void t2() throws InterruptedException {

        ReentrantLock reentrantLock = new ReentrantLock();
        Condition condition = reentrantLock.newCondition();

        new Thread(() -> test(reentrantLock, condition), "A").start();
        new Thread(() -> test(reentrantLock, condition), "B").start();
        new Thread(() -> test(reentrantLock, condition), "C").start();
        // 确保ABC都启动
        Thread.sleep(5000);
        reentrantLock.lock();
        try {
            condition.signalAll();
            System.out.println("可以吃饭了");
        } finally {
            reentrantLock.unlock();
        }
    }

    private static void test(ReentrantLock reentrantLock, Condition condition) {
        reentrantLock.lock();
        try {
            gobbler.cook();
            try {
                condition.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            gobbler.eat();
        } finally {
            reentrantLock.unlock();
        }
    }

    public static class gobbler {
        // 只有一个厨房，同时只能一个人做饭
        public static void cook() {
            System.out.println(Thread.currentThread().getName() + " 正在做饭");
            System.out.println(Thread.currentThread().getName() + " 等待开饭命令");
        }

        public static void eat() {
            System.out.println(Thread.currentThread().getName() + " 正在干饭");
        }

    }


    private static void t1() {
        TicketMachine ticketMachine = new TicketMachine(50);
        new Thread(ticketMachine::ticket, "A").start();
        new Thread(ticketMachine::ticket, "B").start();
        new Thread(ticketMachine::ticket, "C").start();
    }

    /**
     * 售票机
     */
    public static class TicketMachine {


        private Integer count;
        static Lock reentrantLock = new ReentrantLock(false);

        public TicketMachine(Integer count) {
            this.count = count;
        }


        public void ticket() {
            while (count > 0) {
                // 尝试拿锁 (获取成功为 true 否则为false)
                if (reentrantLock.tryLock()) {
                    try {
                        String name = Thread.currentThread().getName();
                        System.out.printf("当前剩余[%d] -- %s卖了一张票\t", count, name);
                        count--;
                        System.out.printf("剩余票数:[%d]\n", count);
                    } finally {
                        reentrantLock.unlock();
                    }
                }
            }
        }
    }
}
